為了生成唯一的Id,React 18 後提供了一個新的 Hook => useId
const id = useId();
他的基本原理表示著,每個 id 都代表該元件在元件樹中的層級結構。

注意:
useId不建議用於當做 HTML 元素列表的 Key,列表的 Key 應該要於你傳入要渲染出畫面的資料有關。
一個簡單的作法,可以使用 useId 產生一個 id,代表某個 DOM 的 Id
function Checkbox() {
  const id = useId();
  return (
    <>
      <label htmlFor={id}>Do you like React?</label>
      <input id={id} type="checkbox" name="react"/>
    </>
  );
};
如果同一元件內的多個 DOM 元素需要時,那麼我們可以先用 useId 產生完代表這個元件的 id,然後再為其加上後綴
function NameFields() {
  const id = useId();
  return (
    <div>
      <label htmlFor={id + '-firstName'}>First Name</label>
      <div>
        <input id={id + '-firstName'} type="text" />
      </div>
      <label htmlFor={id + '-lastName'}>Last Name</label>
      <div>
        <input id={id + '-lastName'} type="text" />
      </div>
    </div>
  );
}
注意:
useId的生成結果字串內會包含:這個符號,用以確保此字串是唯一的,但這樣的字串結果就無法應用在 CSS Selector 或 querySelectorAll 等 API 中,必需要另外定義適合的 Selector。
它和 useEffect 的語法、使用上一模一樣。
會有以下幾點差異:
useLayoutEffect 在 Virtual-DOM 更新完,但在 Render 之前執行,useEffect 則是在 Render 之後執行。useLayoutEffect 是同步執行的,UI 會等 useLayoutEffect 要處理的任務做完才會做 Render。所以不要在 useLayoutEffect 中做需要大量計算的處理,會導致頁面卡頓。useEffect 是異步執行的,UI Render 和 useEffect 不會有有要排隊依序執行的概念。當你希望畫面不要有閃一下的情況時,可以使用
useLayoutEffect,因為他會在 Render 之前執新。但如果在
useLayoutEffect中有大量計算的處理,因為 UI 會等它做完才 Render,這時畫面反而會空白一陣子,造成 UX 體驗不好。有時我們可以透過加上過場效果之類的 UX 解決方式,還是能使用
useEffect完成處理。
function EffectComponent() {
    const [count, setCount] = React.useState(0);
    
    React.useEffect(() => {
        console.log(`useEffect - count=${count}`)
        // 耗時的操作
        const pre = Date.now();
        while(Date.now() - pre < 500) {}
        
        // count為0時重新生成個隨機數
        if (count === 0) {    
            setCount(10 + Math.random() * 200);
        }
    }, [count]);
    
    return (
        <div className= 'EffectComponent' 
          onClick={() => setCount(0)}>
        <h2>EffectComponent</h2>
          <div>{count}</div>
        </div>
    );
}

useEffect 因為是 Render 之後才執行,所以會看到展示 0 的過程
function LayoutEffectComponent() {
    const [count, setCount] = React.useState(0);
    
    React.useLayoutEffect(() => {
        console.log(`useLayoutEffect - count=${count}`)
        // 耗時的操作
        const pre = Date.now();
        while(Date.now() - pre < 500) {}
        
        // count為0時重新生成個隨機數
        if (count === 0) {    
            setCount(10 + Math.random() * 200);
        }
    }, [count]);
    
    return (
        <div className= 'LayoutEffectComponent' 
          onClick={() => setCount(0)}>
        <h2>LayoutEffectComponent</h2>
          <div>{count}</div>
        </div>
    );
}

- 沒有閃爍,當點擊 div,count 更新為0,此時頁面並不會渲染,而是等待
useLayoutEffect內部狀態修改後,才會去更新頁面,所以頁面不會閃爍。- 但是也可以發現頁面更新的比較卡頓,因為
useLayoutEffect會阻塞瀏覽器渲染,正好本例中useLayoutEffect的裡有個耗時操作,所以頁面更新比較卡頓。
完整執行結果:https://codepen.io/lala-lee-jobs/pen/BaxpaqG?editors=0111
接下來介紹跟效能優化有關的二個 Hook - useMemo 及 useCallback,以及一個 Higher-Order Component - React.memo,來幫助我們解決 React Render 時效能上的問題。
https://zh-hans.reactjs.org/docs/hooks-reference.html#useid
https://zh-hant.reactjs.org/docs/hooks-reference.html#uselayouteffect
https://segmentfault.com/a/1190000023396433